package core;

import interfaces.IConnectionHandler;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.KeyStroke;

import shapes.ShapeHandler;

import utilities.ConnectionHandler;
import utilities.FileHandler;
import utilities.ValidateInput;

/******************************************************
Cours :             LOGnnn
Session :           Saison (été, automne, hiver) 200X
Groupe :            n
Projet :            Laboratoire #n
Étudiant(e)(s) :    Marcel Marceau
                    Edith Piaf
Code(s) perm. :     MARM987341987
                    PIAE324398724
Professeur :        Groucho Marx
Date créée :        2002-05-28
Date dern. modif. : 2005-05-01

*******************************************************
Historique des modifications
*******************************************************
 2002-05-28	Cris Fuhrman : Version initiale
 
 2004-03-07	Cris Fuhrman : Intégration de SwingWorker 
               requierant la classe additionnelle 
               SwingWorker.java, utilisation des variables 
               constantes, formatage de code source, 
               organisation des imports, etc.

 2005-05-01	Cris Fuhrman : Intégration de ApplicationSupport
 				requierant la classe additionnelle
 				ApplicationSupport.java et les fichiers
 				prefs.properties, app_xx.properties (où xx est le
 				code de la langue, p. ex. fr = français, en = anglais).
 				Suppression de l'interface Shape.
 				
 2006-05-03	Sébastien Adam :
 
               Uniformisation et maintenance du code.

               Ajout des classes pour la gestion des
               items de menu. Un écouteur ajouté pour chaque item 
               (DemarrerListener, ArreterListener, QuitterListener, 
               AProposDeListener).  
               
               La classe ApplicationSwing n'implémente plus ActionListener. 
               Elle délègue la gestion des items.
               
               Plus besion d'un "if else if" dans la methode actionPerformed pour 
               exécuter l'action associée à un item. Le code est plus
               simple à comprendre, lire et maintenir.	

La distribution originale se trouve à 
https://cours.ele.etsmtl.ca/academique/log120/notesdecours/exemples/lab/lab1/ApplicationSwing.zip
********************************************************/

/**
 * <code>ApplicationSwing</code> est un exemple d'une
 * application en Java qui fournit une interface Swing, avec un simple
 * menu et un dessin.
 *
 * <h4>References</h4> 
 * <ul> 
 *
 * <li>C. Fuhrman, &quot;Notes de cours de LOG120,&quot; &Eacute;cole
 * de technologie sup&eacute;rieure, Montr&eacute;al, Qu&eacute;bec,
 * Canada, 2002
 *
 * <li>Xemacs (for generation of the initial template), <a target="_top" 
 * href="http://www.xemacs.org">www.xemacs.org</a>, 2002 
 *
 * <li><a target="_top" 
 * href="http://java.sun.com/docs/books/tutorial/uiswing/painting/overview.html">Overview
 * of Custom Painting</a>, une partie du tutoriel Java de Sun, 2002.
 *
 * <li>Java Software, <a target="_top" 
 * href="http://java.sun.com/j2se/javadoc/writingdoccomments/index.html">&quot;How
 * to Write Doc Comments for the Javadoc<sup>TM</sup> Tool,&quot;</a>
 * 2002
 *
 * </ul>
 *
 * Distribution originale &agrave; partir du 
 * <a target="_top" href="https://cours.ele.etsmtl.ca/academique/log120/">site Web</a>
 * du cours LOG120.
 * 
 * Created: Tue May 28 11:31:18 2002
 *
 * @author <a href="mailto:christopher.fuhrman@etsmtl.ca">Christopher Fuhrman</a>
 *
 * @version 1.1
 */

public class ApplicationSwing extends JFrame {

	private static final int CANEVAS_HAUTEUR = 500;

	private static final int CANEVAS_LARGEUR = 500;

	private static final int DELAI_QUITTER_MSEC = 200;
	
	private static final int MAX_NOMBRES_DE_FORMES = 10;

	private static final int MARGE_H = 50;

	private static final int MARGE_V = 60;

	private static final int MENU_FICHIER_QUITTER_TOUCHE_MASK = ActionEvent.CTRL_MASK;

	private static final char MENU_FICHIER_QUITTER_TOUCHE_RACC = KeyEvent.VK_Q;
	
	private static final int MENU_FICHIER_OBTENIR_FORMES_MASK = ActionEvent.CTRL_MASK;

	private static final char MENU_FICHIER_OBTENIR_FORMES_RACC = KeyEvent.VK_N;

	private static final String
			MENU_FICHIER_TITRE = "app.frame.menus.file.title",
			MENU_FICHIER_QUITTER = "Exit",
			MENU_AIDE_TITRE = "app.frame.menus.help.title",
			MENU_AIDE_PROPOS = "app.frame.menus.help.about",
			MENU_ORDRE_TITRE = "app.frame.menus.order.title",
			MENU_FICHIER_OB_FORMES = "app.frame.menus.file.getShapes",
		
	
			MENU_ORDER_ID_AS="Par numéro de séquence croissant",
			MENU_ORDER_ID_DE="Par numéro de séquence décroissant",
			MENU_ORDER_TYPE_1="Par type de forme dans l'ordre suivant : carré, rectangle, cercle, ovale, ligne",
			MENU_ORDER_TYPE_2="Par type de forme dans l'ordre inverse",
			MENU_ORDER_AREA_AS="Par aire de forme croissante",
			MENU_ORDER_AREA_DE="Par aire de forme décroissante",
			MENU_ORDER_DISTANCE_MAX="Par distance (croissante) maximale entre deux points",
			MENU_ORDRE_ORIGINAL = "Position Original";
	

	private static final String MESSAGE_DIALOGUE_A_PROPOS = "app.frame.dialog.about";

	private static final long serialVersionUID = 1L;
	
	private String userInput;
	
	private IConnectionHandler connectionHandler;
	
	private ShapeHandler shapeHandler;
	
	
	/* Lancer l'exécution de l'application. */
	public static void main(String[] args) throws InterruptedException {
		
		/* Créer la fenêtre de l'application. */
		ApplicationSwing cadre = new ApplicationSwing();
		
		cadre.startup();
		
		cadre.creerMenuFichier();
		cadre.creerMenuAide();
		cadre.creerMenuOrdre();
		
		/* Centrer la fenêtre. */
		cadre.setLocationRelativeTo(null);
		
		/* Lancer l'application. */
		ApplicationSupport.launch(cadre, ApplicationSupport
				.getResource("app.frame.title"), 0, 0, CANEVAS_LARGEUR
				+ MARGE_H, CANEVAS_HAUTEUR + MARGE_V);
	}
	
	
	/* Traiter l'item "About...". */
	class AProposDeListener implements ActionListener {
		public void actionPerformed(ActionEvent arg0) {
			JOptionPane.showMessageDialog(null, ApplicationSupport
					.getResource(MESSAGE_DIALOGUE_A_PROPOS), ApplicationSupport
					.getResource(MENU_AIDE_PROPOS),
					JOptionPane.INFORMATION_MESSAGE);
		}
	}

	/* Traiter l'item "Stop". */
	class ArreterListener implements ActionListener {
		public void actionPerformed(ActionEvent arg0) {
			//rafraichirMenus();
		}
	}
	
	/* Traiter l'item "Obtenir Formes". */
	class DemarrerListener implements ActionListener {
		
		public void actionPerformed(ActionEvent arg0) {
			shapeHandler = new ShapeHandler(MAX_NOMBRES_DE_FORMES);
			final AbstractSwingWorker worker = new AbstractSwingWorker() {
				public Object construct() {
									
						if(connectionHandler != null) {
						connectionHandler.openConnection(userInput);
							String tempShape = null;
							for(int i = 0; i < 10; i++) {
								tempShape = connectionHandler.getShape();
								if(tempShape != null) {
									shapeHandler.addShape(tempShape);
								}
								else {
									connectionHandler = null;
								}
							}
							
						}
						/*else {
							connectionHandler.closeConnection();
						}*/
					
					
					dessinerFormes();
					
					//rafraichirMenus();
					return new Integer(0);
				}
			};
			worker.start();
			
			//rafraichirMenus();
		}
		
		protected void dessinerFormes(){

				repaint();        
		}
		
	}
	
	/* Traiter l'item "par numéro de séquence croissant...". */
	class ParIdCroissantListener implements ActionListener {
		
		public void actionPerformed(ActionEvent arg0) {
			
			final AbstractSwingWorker worker = new AbstractSwingWorker() {
				public Object construct() {
					dessinerFormes();
					//rafraichirMenus();
					return new Integer(0);
				}
			};
			worker.start();
			//rafraichirMenus();
		}
		
		protected void dessinerFormes(){
		
		shapeHandler.sortByIDasc();	
		repaint();
		
		}
	}
	
	/* Traiter l'item "par numéro de séquence décroissant...". */
	class ParIdDecroissantListener implements ActionListener {
		
		public void actionPerformed(ActionEvent arg0) {
			
			final AbstractSwingWorker worker = new AbstractSwingWorker() {
				public Object construct() {
					dessinerFormes();
					return new Integer(0);
				}
			};
			worker.start();
		}
		
		protected void dessinerFormes(){
		
		shapeHandler.sortByIDdesc();	
		repaint();
		
		}
	}
	
	/* Traiter l'item "par aire de forme croissant...". */
	class ParAireCroissant implements ActionListener {
		
		public void actionPerformed(ActionEvent arg0) {
			
			final AbstractSwingWorker worker = new AbstractSwingWorker() {
				public Object construct() {
					dessinerFormes();
					//rafraichirMenus();
					return new Integer(0);
				}
			};
			worker.start();
			//rafraichirMenus();
		}
		
		protected void dessinerFormes(){
		
		shapeHandler.sortByAreaAsc();	
		repaint();
		
		}
	}
	
	/* Traiter l'item "par aire de forme décroissant...". */
	class ParAireDecroissantListener implements ActionListener {
		
		public void actionPerformed(ActionEvent arg0) {
			
			final AbstractSwingWorker worker = new AbstractSwingWorker() {
				public Object construct() {
					dessinerFormes();
					return new Integer(0);
				}
			};
			worker.start();
		}
		
		protected void dessinerFormes(){
		
		shapeHandler.sortByAreaDesc();	
		repaint();
		
		}
	}
	
	/* Traiter l'item "Par type de forme 1". */
	class ParFormeType1Listener implements ActionListener {
	public void actionPerformed(ActionEvent arg0) {
			
			final AbstractSwingWorker worker = new AbstractSwingWorker() {
				public Object construct() {
					try {
						dessinerFormes();
					} catch (CloneNotSupportedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					return new Integer(0);
				}
			};
			worker.start();
		}
		
		protected void dessinerFormes() throws CloneNotSupportedException{
		
		shapeHandler.sortByFormeType1();
		repaint();
		
		}
	}
	
	/* Traiter l'item "Par type de forme 2". */
	class ParFormeType2Listener implements ActionListener {
	public void actionPerformed(ActionEvent arg0) {
			
			final AbstractSwingWorker worker = new AbstractSwingWorker() {
				public Object construct() {
					try {
						dessinerFormes();
					} catch (CloneNotSupportedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					return new Integer(0);
				}
			};
			worker.start();
		}
		
		protected void dessinerFormes() throws CloneNotSupportedException{
		
		shapeHandler.sortByFormeType2();
		repaint();
		
		}
	} 
	
	/* Traiter l'item "Par Distance Maximanle entre deux points". */
	class ParDistanceMaxListener implements ActionListener {
	public void actionPerformed(ActionEvent arg0) {
			
			final AbstractSwingWorker worker = new AbstractSwingWorker() {
				public Object construct() {
					try {
						dessinerFormes();
					} catch (CloneNotSupportedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					return new Integer(0);
				}
			};
			worker.start();
		}
		
		protected void dessinerFormes() throws CloneNotSupportedException{
		
		shapeHandler.sortByDistance();
		repaint();
		
		}
	} 
	
	
	/* Traiter l'item "Exit". */
	class QuitterListener implements ActionListener {
		public void actionPerformed(ActionEvent arg0) {

				try {
					Thread.sleep(DELAI_QUITTER_MSEC);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			
			if(connectionHandler != null) {
				connectionHandler.closeConnection();
			}
			System.exit(0);
		}
	}
	
	/* Traiter l'item "Position originale". */
	class PositionOriginaleListener implements ActionListener {
	public void actionPerformed(ActionEvent arg0) {
			
			final AbstractSwingWorker worker = new AbstractSwingWorker() {
				public Object construct() {
					try {
						dessinerFormes();
					} catch (CloneNotSupportedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					return new Integer(0);
				}
			};
			worker.start();
		}
		
		protected void dessinerFormes() throws CloneNotSupportedException{
		
		shapeHandler.getOriginalList();
		repaint();
		
		}
	}

	
	/* Créer le panneau sur lequel les formes sont dessinées. */
	class CustomCanvas extends JPanel {
		private static final long serialVersionUID = 1L;

		public CustomCanvas() {
			setSize(getPreferredSize());
			setMinimumSize(getPreferredSize());
			CustomCanvas.this.setBackground(Color.white);
		}

		public Dimension getPreferredSize() {
			return new Dimension(CANEVAS_LARGEUR, CANEVAS_HAUTEUR);
		}

		public void paintComponent(Graphics graphics) {
			super.paintComponent(graphics);

			if(!shapeHandler.isEmpty()) {
				shapeHandler.draw(graphics);
			}
			
		}
		
	}
	
	/* - Constructeur - Créer le cadre dans lequel les formes sont dessinées. */
	public ApplicationSwing() {
		getContentPane().add(new JScrollPane(new CustomCanvas()));
	}


	/* Créer le menu "File". */
	private JMenu creerMenuFichier() {
		JMenu menu = ApplicationSupport.addMenu(this, MENU_FICHIER_TITRE,
				new String[] { MENU_FICHIER_OB_FORMES});
		
		menu.add(new JSeparator()); // SEPARATOR
		menu.add(MENU_FICHIER_QUITTER);
		
		menu.getItem(0).addActionListener(new DemarrerListener());
		menu.getItem(0).setAccelerator(
				KeyStroke.getKeyStroke(MENU_FICHIER_OBTENIR_FORMES_RACC,
						MENU_FICHIER_OBTENIR_FORMES_MASK));
		
		menu.getItem(2).addActionListener(new QuitterListener());
		menu.getItem(2).setAccelerator(
				KeyStroke.getKeyStroke(MENU_FICHIER_QUITTER_TOUCHE_RACC,
						MENU_FICHIER_QUITTER_TOUCHE_MASK));
		
				
		return menu;
	}

	/* Créer le menu "Help". */
	private JMenu creerMenuAide() {
		JMenu menu = ApplicationSupport.addMenu(this, MENU_AIDE_TITRE,
				new String[] { MENU_AIDE_PROPOS });
		
		menu.getItem(0).addActionListener(new AProposDeListener());
		
		return menu;
	}
	
	/* Créer le menu "Ordre". */
	private JMenu creerMenuOrdre() {
		
		
		JMenu menu = ApplicationSupport.addMenu(this, MENU_ORDRE_TITRE,
				new String[] {});
		
		ButtonGroup group = new ButtonGroup();
		
		JRadioButtonMenuItem byIdAsc = new JRadioButtonMenuItem(MENU_ORDER_ID_AS);
		byIdAsc.setSelected(false);
		group.add(byIdAsc);
		
		JRadioButtonMenuItem byIdDes = new JRadioButtonMenuItem(MENU_ORDER_ID_DE);
		byIdDes.setSelected(false);
		group.add(byIdDes);	
		
		JRadioButtonMenuItem byAreaAs = new JRadioButtonMenuItem(MENU_ORDER_AREA_AS);
		byAreaAs.setSelected(false);
		group.add(byAreaAs);
		
		JRadioButtonMenuItem byAreaDes = new JRadioButtonMenuItem(MENU_ORDER_AREA_DE);
		byAreaDes.setSelected(false);
		group.add(byAreaDes);
		
		JRadioButtonMenuItem byFormeType1 = new JRadioButtonMenuItem(MENU_ORDER_TYPE_1);
		byFormeType1.setSelected(false);
		group.add(byFormeType1);
		
		JRadioButtonMenuItem byFormeType2 = new JRadioButtonMenuItem(MENU_ORDER_TYPE_2);
		byFormeType2.setSelected(false);
		group.add(byFormeType2);
		
		JRadioButtonMenuItem byDistanceAsc = new JRadioButtonMenuItem(MENU_ORDER_DISTANCE_MAX);
		byDistanceAsc.setSelected(false);
		group.add(byDistanceAsc);	
		
		JRadioButtonMenuItem originalForme = new JRadioButtonMenuItem(MENU_ORDRE_ORIGINAL);
		byDistanceAsc.setSelected(false);
		group.add(originalForme);
		
		menu.add(byIdAsc);
		menu.add(byIdDes);
		menu.add(byAreaAs);
		menu.add(byAreaDes);
		menu.add(byFormeType1);
		menu.add(byFormeType2);
		menu.add(byDistanceAsc);
		menu.add(new JSeparator()); // SEPARATOR
		menu.add(originalForme);
		
		menu.getItem(0).addActionListener(new ParIdCroissantListener());
		menu.getItem(1).addActionListener(new ParIdDecroissantListener());
		menu.getItem(2).addActionListener(new ParAireCroissant());
		menu.getItem(3).addActionListener(new ParAireDecroissantListener());
		menu.getItem(4).addActionListener(new ParFormeType1Listener());
		menu.getItem(5).addActionListener(new ParFormeType2Listener());
		menu.getItem(6).addActionListener(new ParDistanceMaxListener());
		menu.getItem(8).addActionListener(new PositionOriginaleListener());
		
		return menu;
		
	}

	/**
	 * Initialiser les objets principaux.
	 */
	public void startup() {
		//shapeNodeList = new ShapeNodeList(MAX_NOMBRES_DE_FORMES);
		shapeHandler = new ShapeHandler(MAX_NOMBRES_DE_FORMES);
		
		do {
			/*userInput = JOptionPane.showInputDialog("Quel est le nom d'hôte et le port du serveur de formes?\n"
					+ "Vous pouvez également entrer le chemin de votre fichier *.txt");*/
			userInput = JOptionPane.showInputDialog("Quel est le nom d'hôte et le port du serveur de formes?");
			if(userInput == null)
				System.exit(0);
		}
		while(!ValidateInput.isServerAddress(userInput) && !ValidateInput.isTextFile(userInput));
		
		if(ValidateInput.isServerAddress(userInput)) {
			connectionHandler = new ConnectionHandler();
			//connectionHandler.openConnection(userInput);
		}
		/*else if(ValidateInput.isTextFile(userInput)) {
			connectionHandler = new FileHandler();
			connectionHandler.openConnection(userInput);
		}*/
		
	}
	
}